package com.eastfair.home.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.home.dao.VenueReportMapper;
import com.eastfair.home.dto.VenueReportDTO;
import com.eastfair.home.entity.VenueReport;
import com.eastfair.home.enumeration.VenueReportReportDrawingStatusEnum;
import com.eastfair.home.enumeration.VenueReportReportServiceStatusEnum;
import com.eastfair.home.exceptioncode.HomeExceptionCode;
import com.eastfair.home.service.HomeServiceProviderSpaceService;
import com.eastfair.home.service.VenueReportDrawingService;
import com.eastfair.home.service.VenueReportService;
import com.eastfair.home.vo.VenueReportVO;
import com.eastfair.venuebooking.api.ServiceBookingFeign;
import com.eastfair.venueservice.dto.ServiceBookingQuery;
import com.eastfair.venueservice.enumeration.ServiceBookingReportSpaceStatusEnum;
import com.eastfair.venueservice.vo.ServiceBookingVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 一键报馆记录
 * </p>
 *
 * @author dq
 * @date 2022-10-31
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class VenueReportServiceImpl extends SuperServiceImpl<VenueReportMapper, VenueReport> implements VenueReportService {

    @Resource
    private HomeServiceProviderSpaceService homeServiceProviderSpaceService;

    @Resource
    private VenueReportDrawingService venueReportDrawingService;

    @Resource
    private ServiceBookingFeign serviceBookingFeign;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<VenueReport> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(VenueReport model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        if (model.getReportDrawingStatus() == null) {
            model.setReportDrawingStatus(VenueReportReportDrawingStatusEnum.NOT_REPORT);
        }
        if (model.getReportServiceStatus() == null) {
            model.setReportServiceStatus(VenueReportReportServiceStatusEnum.NOT_REPORT);
        }
        return R.successDef();
    }

    @Override
    public List<VenueReportVO> listVenueReportVO(VenueReportDTO query) {
        log.info("listVenueReportVO - 查询主场报馆列表VO, query={}", query);
        // 查询主场在该展会下的展馆编码
        List<String> spaceCodeList
                = homeServiceProviderSpaceService.listSpaceCodesByServiceProviderId(query.getHomeId(), query.getExhibitionManageId());
        if (spaceCodeList == null || spaceCodeList.isEmpty()) {
            return Collections.emptyList();
        }
        query.setSpaceCodeList(spaceCodeList);
        List<VenueReport> list = listVenueReport(query);
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        // 已报馆服务数量
        ServiceBookingQuery serviceBookingQuery = new ServiceBookingQuery();
        serviceBookingQuery.setExhibitionManageId(query.getExhibitionManageId());
        R<List<ServiceBookingVO>> queryReportServiceCount = serviceBookingFeign.queryReportServiceCount(serviceBookingQuery);
        if(!queryReportServiceCount.getIsSuccess()){
            throw BizException.wrap(queryReportServiceCount.getCode(),queryReportServiceCount.getMsg());
        }
        Map<String, ServiceBookingVO> serviceBookingVOMap = new HashMap<>(8);
        List<ServiceBookingVO> data = queryReportServiceCount.getData();
        if (CollectionUtils.isNotEmpty(data)) {
            serviceBookingVOMap = data.stream().collect(Collectors.toMap(e->e.getSpaceName()+"-"+e.getReportSpaceStatus().getCode(), Function.identity()));
        }
        Map<String, ServiceBookingVO> finalServiceBookingVOMap = serviceBookingVOMap;
        return list
                .stream()
                .map(venueReport -> {
                    VenueReportVO venueReportVO = BeanUtil.toBean(venueReport, VenueReportVO.class);
                    // 处理报馆服务数量
                    dealServiceReportNum(finalServiceBookingVOMap, venueReportVO);
                    return venueReportVO;
                })
                .filter(e -> Objects.isNull(query.getReportServiceStatus()) || e.getReportServiceStatus().eq(query.getReportServiceStatus()))
                .collect(Collectors.toList());
    }

    /**
     * 处理报馆服务数量
     * @param finalServiceBookingVOMap finalServiceBookingVOMap
     * @param venueReportVO venueReportVO
     */
    private void dealServiceReportNum(Map<String, ServiceBookingVO> finalServiceBookingVOMap, VenueReportVO venueReportVO) {
        String spaceName = venueReportVO.getSpaceName();
        // 已报馆数量
        ServiceBookingVO reportedNum = finalServiceBookingVOMap.get(spaceName + "-" + ServiceBookingReportSpaceStatusEnum.REPORTED.getCode());
        // 未报馆数量
        ServiceBookingVO notReportedNum = finalServiceBookingVOMap.get(spaceName + "-" + ServiceBookingReportSpaceStatusEnum.NOT_REPORTED.getCode());
        if (Objects.nonNull(reportedNum)) {
            venueReportVO.setHasReportServiceCount(reportedNum.getBookingNum().intValue());
        } else {
            venueReportVO.setHasReportServiceCount(0);
        }
        if (Objects.nonNull(notReportedNum)) {
            venueReportVO.setNotReportDrawingCount(notReportedNum.getBookingNum().intValue());
        } else {
            venueReportVO.setNotReportDrawingCount(0);
        }
        if (venueReportVO.getHasReportServiceCount() != 0 && venueReportVO.getNotReportDrawingCount() != 0) {
            // 即存在未报馆服务，也存在已报馆服务，则为部分报馆
            venueReportVO.setReportServiceStatus(VenueReportReportServiceStatusEnum.PARTIAL_REPORT);
        } else if (venueReportVO.getHasReportServiceCount() != 0 && venueReportVO.getNotReportDrawingCount() == 0) {
            // 均为已报馆，则为已报馆
            venueReportVO.setReportServiceStatus(VenueReportReportServiceStatusEnum.HAS_REPORT);
        }else {
            venueReportVO.setReportServiceStatus(VenueReportReportServiceStatusEnum.NOT_REPORT);
        }
    }

    @Override
    public List<VenueReport> listVenueReport(VenueReportDTO query) {
        log.info("listVenueReport - 查询主场报馆记录, query={}", query);
        QueryWrapper<VenueReport> queryWrapper = createQueryWrapperVenueReport(query);
        return list(queryWrapper);
    }

    @Override
    public List<String> listSpaceCodeByExhibitionManageId(Long exhibitionManageId, Long homeId) {
        VenueReportDTO query = new VenueReportDTO();
        query.setExhibitionManageId(exhibitionManageId);
        query.setHomeId(homeId);
        List<VenueReport> venueReportList = listVenueReport(query);
        if (venueReportList == null || venueReportList.isEmpty()) {
            return Collections.emptyList();
        }
        return venueReportList
                .stream()
                .map(VenueReport::getSpaceCode)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VenueReport saveVenueReport(VenueReportDTO venueReportDTO) {
        log.info("saveVenueReport - 保存主场报馆记录, venueReportDTO={}", venueReportDTO);
        VenueReport venueReport = BeanUtil.toBean(venueReportDTO, VenueReport.class);
        save(venueReport);
        return venueReport;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(List<VenueReportDTO> list) {
        log.info("saveBatch - 批量保存主场报馆记录, list={}", list);
        if (list == null || list.isEmpty()) {
            return false;
        }
        Map<Long, Map<Long, List<String>>> existVenueReportMap = getExistVenueReportMap(list);
        for (VenueReportDTO venueReportDTO : list) {
            Map<Long, List<String>> homeVenueReportMap = existVenueReportMap.get(venueReportDTO.getExhibitionManageId());
            // 没有此展会的报馆记录，可以新增
            if (homeVenueReportMap == null) {
                saveVenueReport(venueReportDTO);
                continue;
            }
            List<String> spaceCodeList = homeVenueReportMap.get(venueReportDTO.getHomeId());
            // 展会没有此主场的报馆记录，可以新增
            if (spaceCodeList == null || spaceCodeList.isEmpty()) {
                saveVenueReport(venueReportDTO);
                continue;
            }
            // 负责展会的主场没有此展厅的报馆记录，可以新增
            if (!spaceCodeList.contains(venueReportDTO.getSpaceCode())) {
                saveVenueReport(venueReportDTO);
            }
            // 负责展会的主场已经有了此展厅的报馆记录，不需要新增
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VenueReport updateVenueReport(VenueReportDTO venueReportDTO) {
        log.info("updateVenueReport - 更新主场报馆记录, venueReportDTO={}", venueReportDTO);
        VenueReport venueReport = BeanUtil.toBean(venueReportDTO, VenueReport.class);
        updateById(venueReport);
        return venueReport;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateReportDrawingStatus(Long id) {
        log.info("updateReportDrawingStatus - 更新报馆图纸状态, id={}", id);
        VenueReport venueReport = getById(id);
        if (venueReport == null) {
            throw BizException.wrap(HomeExceptionCode.REPORT_VENUE_SPACE_NOT_EXIST);
        }
        VenueReportReportDrawingStatusEnum reportDrawingStatus
                = venueReportDrawingService.getReportDrawingStatus(venueReport.getExhibitionManageId(), venueReport.getSpaceCode(), venueReport.getId());
        venueReport.setReportDrawingStatus(reportDrawingStatus);
        return updateById(venueReport);
    }

    @Override
    public boolean updateReportServiceStatus(Long id) {
        return false;
    }

    private QueryWrapper<VenueReport> createQueryWrapperVenueReport(VenueReportDTO query) {
        QueryWrapper<VenueReport> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(VenueReport::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(StrUtil.isNotBlank(query.getSpaceCode()), VenueReport::getSpaceCode, query.getSpaceCode())
                .eq(query.getReportDrawingStatus() != null, VenueReport::getReportDrawingStatus, query.getReportDrawingStatus())
                .eq(query.getExhibitionManageId() != null, VenueReport::getExhibitionManageId, query.getExhibitionManageId())
                .eq(query.getHomeId() != null, VenueReport::getHomeId, query.getHomeId())
                .in(query.getSpaceCodeList() != null && !query.getSpaceCodeList().isEmpty(),
                        VenueReport::getSpaceCode, query.getSpaceCodeList())
        ;
        return queryWrapper;
    }

    /**
     * 查询已经存在的主场报馆记录, 组成map.
     *
     * @param list VenueReportDTO列表
     * @return Map<展会ID, Map<主场ID, List<展厅编码>>>
     */
    private Map<Long, Map<Long, List<String>>> getExistVenueReportMap(List<VenueReportDTO> list) {
        Map<Long, Map<Long, List<String>>> exhibitionVenueReportMap = new HashMap<>(16);
        for (VenueReportDTO venueReportDTO : list) {
            Map<Long, List<String>> homeVenueReportMap = exhibitionVenueReportMap.get(venueReportDTO.getExhibitionManageId());
            // 没有查询过此展会下的报馆记录，则查询负责此展会的此主场的报馆记录
            if (homeVenueReportMap == null) {
                List<String> spaceCodeList = listSpaceCodeByExhibitionManageId(venueReportDTO.getExhibitionManageId(), venueReportDTO.getHomeId());
                homeVenueReportMap = new HashMap<>(16);
                homeVenueReportMap.put(venueReportDTO.getHomeId(), spaceCodeList);
                exhibitionVenueReportMap.put(venueReportDTO.getExhibitionManageId(), homeVenueReportMap);
                continue;
            }
            // 查询过此展会下的报馆记录，没查询过负责此展会的此主场的报馆记录，则查询负责此展会的此主场的报馆记录
            if (!homeVenueReportMap.containsKey(venueReportDTO.getHomeId())) {
                List<String> spaceCodeList = listSpaceCodeByExhibitionManageId(venueReportDTO.getExhibitionManageId(), venueReportDTO.getHomeId());
                homeVenueReportMap.put(venueReportDTO.getHomeId(), spaceCodeList);
            }
            // 查询过负责此展会的主场的报馆记录，不需要查询
        }
        return exhibitionVenueReportMap;
    }
}
